package com.hylanda.processors.hlMailSenderPlus;

import com.alibaba.fastjson.JSONArray;
import net.minidev.json.JSONObject;
import net.minidev.json.JSONValue;

import java.text.Collator;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by GuoMeng on 2019/1/8.
 */
public class MailData{
    /*邮件配置*/
    protected MailConfig config;
    /*记录全部数据字段*/
    protected Set<String> oKeys;
    /*数据缓存*/
    protected ArrayList<JSONObject> oData;
    /*统计表的统计维度*/
    protected JSONObject count;


    public MailData( MailConfig _conf ){
        config  = _conf;
        count   = ( JSONObject )JSONValue.parse( _conf.getValue( MailConfig.MAIL_COUNT ) );
        oKeys   = new HashSet();
        oData   = new ArrayList<>();
    }

    /**
     * 新增一条数据
     * @param data
     */
    public void addNew( JSONObject data ){
        oKeys.addAll( data.keySet() );
        oData.add( data );
    }

    /**
     * 获取全部数据
     * @return
     */
    public ArrayList<JSONObject> getAll(){
        String dataOrder    = config.getValue( MailConfig.MAIL_ATTR_ORDER );
        if( null != dataOrder && dataOrder != "null" && this.oKeys.contains( dataOrder ) ){
            HashMap<String, List> orderValue    = new HashMap<>();
            orderValue.put( "___Empty___", new ArrayList<JSONObject>() );
            for( JSONObject _d : oData ){
                String _v       = _d.getAsString( dataOrder );
                if( _v != null ){
                    if( !orderValue.containsKey( _v ) )
                        orderValue.put( _v, new ArrayList<JSONObject>() );
                    orderValue.get( _v ).add( _d );
                }else
                    orderValue.get( "___Empty___" ).add( _d );
            }

            List<String> orderKey        = new ArrayList( orderValue.keySet() );
            Collections.sort( orderKey, new Comparator<Object>() {
                Collator cmp    = Collator.getInstance( java.util.Locale.CHINA );
                @Override
                public int compare( Object o1, Object o2 ){
                    String k1   = String.valueOf( o1 );
                    String k2   = String.valueOf( o2 );
                    if( k1 == null )
                        return -1;
                    if( k2 == null )
                        return 1;

                    if( cmp.compare( k1, k2 ) > 0 )
                        return 1;
                    return -1;
                }
            });

            oData.clear();
            for( String _k : orderKey ){
                if( !_k.equals( "___Empty___" ) )
                    oData.addAll( orderValue.get( _k ) );
            }
            oData.addAll( orderValue.get( "___Empty___" ) );
        }
        return oData;
    }

    /**
     * 获取待发送数据量
     * @return
     */
    public int count(){
        return oData.size();
    }

    /**
     * 获取待发送数据字段列表
     * 用于生成邮件附件
     * @return
     */
    public Set<String> keySet(){
        return oKeys;
    }

    /**
     * 内容串行化
     * @return
     */
    public String toString(){
        HashMap<String, Object> data    = new HashMap<>();
        data.put( "data", oData );
        data.put( "lastSendTime", config.getLastSend() );
        return com.alibaba.fastjson.JSONObject.toJSONString( data );
    }

    public static MailData fromString(hlMailSenderProcessor hlMailSenderProcessor, MailConfig _conf, String JsonString ){
        MailData obj        = new MailData( _conf );
        try{
            com.alibaba.fastjson.JSONObject content
                            = (com.alibaba.fastjson.JSONObject) com.alibaba.fastjson.JSONObject.parse( JsonString );

            String _data    = ( ( JSONArray )content.get( "data" ) ).toJSONString();
            Object objdata  = JSONValue.parse( _data );
            if( objdata instanceof net.minidev.json.JSONArray){//输入数据为JSON数组
                net.minidev.json.JSONArray datas     = (net.minidev.json.JSONArray)objdata;
                for( Object data : datas ){
                    obj.addNew( (JSONObject) data );
                }
            } else if (objdata instanceof JSONObject) {//数据为单条json格式
                obj.addNew( (JSONObject) objdata );
            }

            obj.config.setLastSend( new SimpleDateFormat( "yyyy-MM-dd  HH:mm:ss" ).parse( String.valueOf( content.get( "lastSendTime" ) ) ).getTime() );
        }catch( Exception e ){
            hlMailSenderProcessor.wirteError( "从缓存初始化数据失败!" + e.getMessage() );
        }
        return obj;
    }

    /**
     * 处理邮件内容
     * @return
     */
    public HashMap<String, Object> make(){
        /*消重字段*/
        String sFilter                  = config.getValue( MailConfig.MAIL_FILTER );
        /*正文数据上限*/
        int nDataLimit                  = Integer.valueOf( config.getValue( MailConfig.MAIL_LIMIT ) );
        /*格式化正文配置,计算需要在邮件中输出的字段*/
        Matcher matcherContent          = getTagConf( config.getValue( MailConfig.MAIL_MESSAGE ) );
        ArrayList<String> _contentConf  = new ArrayList<>();
        while( matcherContent.find() ){
            String _key     = matcherContent.group( 1 );
            if( !_key.isEmpty() )
                _contentConf.add( _key );
        }

        /*标题格式化配置，计算需要统计的数据范围*/
        String sTitle               = config.getValue( MailConfig.MAIL_SUBJECT );
        Matcher matcherTitle        = getTagConf( sTitle );
        StatisticsConfig sConf      = new StatisticsConfig( matcherTitle );
        ArrayList<Object> _tcFilter = new ArrayList<>();


        /*用于生成统计表格的结果*/
        HashMap<String, AtomicInteger> dataCount  = new HashMap<>();

        String sContent                 = "";
        HashMap<String, Object> rst     = new HashMap<>();
        if( !oData.isEmpty() ){
            AtomicInteger _num          = new AtomicInteger( 0 );       //统计已处理的数据条数
            for( JSONObject _d : oData ){
                /*消重处理*/
                if( !sFilter.isEmpty() && _d.containsKey( sFilter ) ){
                    if( _tcFilter.contains( _d.get( sFilter ) ) )
                        continue;
                    else
                        _tcFilter.add( _d.get( sFilter ) );
                }
                /*计算统计表*/
                getCount( _d, dataCount );
                /*判断发送条数是否达到上限*/
                int _curNum     = _num.getAndIncrement();

                String _s       = config.getValue( MailConfig.MAIL_MESSAGE );
                for( String _key : _d.keySet() ){
                    String _v   = String.valueOf( _d.getOrDefault( _key, "" ) );
                    _v          = quoteReplacement( _v );
                    if( nDataLimit >= 0 && _curNum < nDataLimit ){
                        if( _contentConf.contains( _key ) ){
                        /*使用变量替换MESSAGE中的%标签%*/
                            _s              = _s.replaceAll( "%" + _key + "%", _v );
                        }
                    }
                    if( sConf.max.containsKey( _key ) ){
                            /*统计字段最大值*/
                        if( sConf.max.get( _key ).isEmpty() )
                            sConf.max.put( _key, _v );
                        else if( sConf.max.get( _key ).compareTo( _v ) < 0 )
                            sConf.max.put( _key, _v );
                    }
                    if( sConf.min.containsKey( _key ) ){
                            /*统计字段最小值*/
                        if( sConf.min.get( _key ).isEmpty() )
                            sConf.min.put( _key, _v );
                        else if( sConf.min.get( _key ).compareTo( _v ) > 0 )
                            sConf.min.put( _key, _v );
                    }
                }
                if( nDataLimit >= 0 && _curNum < nDataLimit ){
                    sContent        += _s;
                }
                sConf.numReal.getAndIncrement();
            }
        }

        /*格式化邮件主题*/
        rst.put( MailConfig.MAIL_SUBJECT, makeSubject( sConf, sTitle ) );
        rst.put( MailConfig.MAIL_MESSAGE, sContent );
        rst.put( MailConfig.DATA_STAT, makeCountTb( dataCount ) );
        rst.put( MailConfig.MAIL_LIMIT, config.getValue( MailConfig.MAIL_LIMIT ) );
        return rst;
    }

    /**
     * 并清空待发送队列
     */
    public void clearData(){
        oData.clear();
        oKeys.clear();
    }

    /**
     * 统计配置项
     */
    protected class StatisticsConfig extends HashMap<String, Object>{
        public ArrayList<String> num        = new ArrayList<>();
        public HashMap<String, String> min  = new HashMap<>();
        public HashMap<String, String> max  = new HashMap<>();
        public AtomicInteger numReal        = new AtomicInteger( 0 );

        public StatisticsConfig( Matcher mConf ){
            while( mConf.find() ){
                String _key     = mConf.group( 1 );
                if( !_key.isEmpty() ){
                    String[] _s   = _key.split( "_" );
                    switch ( _s[0] ){
                        case "NUMALL"   :
                            num.add( "ALL" ); break;
                        case "NUMREAL"  :
                            num.add( "REAL" ); break;
                        case "DATAMAX"  :
                            max.put( _key.substring( "DATAMAX_".length(), _key.length() ), ""  ); break;
                        case "DATAMIN"  :
                            min.put( _key.substring( "DATAMIN_".length(), _key.length() ), ""  ); break;
                    }
                }
            }
        }
    }

    /**
     * 获取标签配置
     * @param sConf
     * @return
     */
    protected Matcher getTagConf( String sConf ){
        Pattern pattern                 = Pattern.compile( "%([0-9,a-z,A-Z,_]+)%" );
        return pattern.matcher( sConf );
    }

    /**
     * 生成邮件主题
     * @param conf
     * @param sTitleTpl
     * @return
     */
    protected String makeSubject( StatisticsConfig conf, String sTitleTpl ){
        String sTitle       = sTitleTpl;
        if( conf.num.contains( "ALL" ) )
            sTitle  = sTitle.replaceAll( "%NUMALL%", String.valueOf( oData.size() ) );
        if( conf.num.contains( "REAL" ) )
            sTitle  = sTitle.replaceAll( "%NUMREAL%", String.valueOf( conf.numReal.get() ) );
        if( !conf.max.isEmpty() ){
            for( String _key : conf.max.keySet() ){
                sTitle  = sTitle.replace( "%DATAMAX_" + _key + "%", conf.max.get( _key ) );
            }
        }
        if( !conf.min.isEmpty() ){
            for( String _key : conf.min.keySet() ){
                sTitle  = sTitle.replace( "%DATAMIN_" + _key + "%", conf.min.get( _key ) );
            }
        }
        return sTitle;
    }

    /**
     * 计算数据统计表
     * @param data
     * @param dataCount
     */
    protected void getCount( JSONObject data, HashMap<String, AtomicInteger> dataCount ){
        String _key             = count.getAsString( "tag" );
        List<String> _vals      = Arrays.asList( count.getAsString( "val" ).split( "," ) );
        String _v               = data.getAsString( _key );
        if( _vals.size() == 1 && _vals.get( 0 ).equals( "*" ) ){
        }else{
            if( _vals.indexOf( _v ) < 0 )
                _v      = null;
        }

        if( _v != null ){
            if( !dataCount.containsKey( _v ) )
                dataCount.put( _v, new AtomicInteger( 0 ) );
            dataCount.get( _v ).getAndIncrement();
        }
    }

    /**
     * 生成数据统计表
     * @param dataCount
     * @return
     */
    protected String makeCountTb( HashMap<String, AtomicInteger> dataCount ){
        List<String> _vals      = Arrays.asList( count.getAsString( "val" ).split( "," ) );
        List<String> primary    = Arrays.asList( count.getAsString( "pri" ).split( "," ) );
        String rst              = "";
        String firstLine        = "<tr><td></td><td>合计</td></tr>";
        String htmlBody         = "";
        String lastLine         = "";
        int total               = 0;
        if( _vals.size() == 1 && _vals.get( 0 ).equals( "*" ) ){
            _vals       = Arrays.asList( dataCount.keySet().toArray( new String[0] ) );
        }

        for( String _k : _vals ){
            if( _k.isEmpty() ){
                htmlBody    += "<tr><td>&nbsp;</td><td>&nbsp;</td></tr>";
            }else{
                String cls  = primary.indexOf( _k ) >= 0 ? "color:red;" : "";
                int _v      = dataCount.containsKey( _k ) ? dataCount.get( _k ).get() : 0;
                htmlBody    += "<tr><td style='"+cls+"'>"+_k+"</td><td style='"+cls+"'>" + String.valueOf( _v ) + "</td></tr>";
                total       += _v;
            }
        }
        lastLine            += "<tr><td>合计:</td><td>"+String.valueOf( total )+"</td></tr>";
        rst     = "<table>" +
                "<thead>" + firstLine + "</thead>" +
                "<tbody>" + htmlBody + lastLine + "</tbody>" +
                "</table>";

        return rst;
    }

    /**
     * 过滤数据中的"\"和"$"
     * @param s
     * @return
     */
    public static String quoteReplacement( String s ){
        if( ( s.indexOf( '\\' ) == -1 ) && ( s.indexOf( '$' ) == -1 ) )
            return s;
        StringBuilder sb    = new StringBuilder();
        for( int i = 0; i < s.length(); i++ ){
            char c  = s.charAt(i);
            if( c == '\\' || c == '$' ){
                sb.append('\\');
            }
            sb.append( c );
        }
        return sb.toString();
    }
}